
package com.hlkj.pay.service.merchant.impl;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.hlkj.framework.common.pojo.PageResult;
import com.hlkj.framework.common.util.collection.CollectionUtils;
import com.hlkj.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.hlkj.framework.mybatis.core.query.QueryWrapperX;
import com.hlkj.framework.mybatis.core.utils.MyBatisUtils;
import com.hlkj.pay.dto.fund.FundAccountQueryDto;
import com.hlkj.pay.dto.fund.MerchantFundPageDto;
import com.hlkj.pay.dto.merchant.fund.MerchantFundAccountDto;
import com.hlkj.pay.enums.CommonEnum;
import com.hlkj.pay.enums.MerchantEnum;
import com.hlkj.pay.infrastructure.mapper.merchant.MerchantCardMapper;
import com.hlkj.pay.infrastructure.mapper.merchant.MerchantCertInfoMapper;
import com.hlkj.pay.infrastructure.mapper.merchant.MerchantLicenseMapper;
import com.hlkj.pay.infrastructure.mapper.merchant.fund.MerchantFundAccountBindMapper;
import com.hlkj.pay.infrastructure.mapper.merchant.fund.MerchantFundAccountMapper;
import com.hlkj.pay.infrastructure.model.merchant.MerchantCardDO;
import com.hlkj.pay.infrastructure.model.merchant.MerchantCertInfoDO;
import com.hlkj.pay.infrastructure.model.merchant.MerchantLicenseDO;
import com.hlkj.pay.infrastructure.model.merchant.fund.MerchantFundAccountBindDO;
import com.hlkj.pay.infrastructure.model.merchant.fund.MerchantFundAccountDO;
import com.hlkj.pay.service.CommonSnFilterService;
import com.hlkj.pay.service.merchant.IMerchantFundAccountService;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2025/01/08 17:07
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class MerchantFundAccountServiceImpl extends CommonSnFilterService implements IMerchantFundAccountService {

    private final MerchantCertInfoMapper merchantCertInfoMapper;

    private final MerchantLicenseMapper merchantLicenseMapper;

    private final MerchantCardMapper merchantCardMapper;

    private final MerchantFundAccountBindMapper merchantFundAccountBindMapper;

    private final MerchantFundAccountMapper merchantFundAccountMapper;

    @Override
    public Long saveFund(MerchantFundAccountDto merchantFundAccountDto) {
        // 主表
        MerchantFundAccountDO merchantReportInfoDO = merchantFundAccountDto.getMerchantFundAccount();
        merchantFundAccountMapper.insert(merchantReportInfoDO);
        // 报备营业执照信息
        MerchantLicenseDO merchantReportLicenseDO = merchantFundAccountDto.getMerchantFundLicense();
        // 报备法人信息
        MerchantCertInfoDO merchantReportLegalDO = merchantFundAccountDto.getMerchantFundLegal();
        // 联系人信息
        MerchantCertInfoDO merchantReportContactDO = merchantFundAccountDto.getMerchantFundContact();
        // 报备结算卡信息
        MerchantCardDO merchantReportCardDO = merchantFundAccountDto.getMerchantFundCard();
        if (merchantReportLicenseDO != null) {
            merchantReportLicenseDO.setRelationId(merchantReportInfoDO.getId());
            merchantReportLicenseDO.setRelationType(MerchantEnum.MERCHANT_COMMON_RELATION_TYPE.FUND.getCode());
            merchantReportLicenseDO.setSn(merchantReportInfoDO.getSn());
        }
        if (merchantReportCardDO != null) {
            merchantReportCardDO.setRelationId(merchantReportInfoDO.getId());
            merchantReportCardDO.setRelationType(MerchantEnum.MERCHANT_COMMON_RELATION_TYPE.FUND.getCode());
            merchantReportCardDO.setSn(merchantReportInfoDO.getSn());
        }
        List<MerchantCertInfoDO> merchantReportCertInfoList = new ArrayList<>();
        if (merchantReportLegalDO != null) {
            merchantReportLegalDO.setType(MerchantEnum.CERT_INFO_TYPE.LEGAL.getCode());
            merchantReportLegalDO.setRelationType(MerchantEnum.MERCHANT_COMMON_RELATION_TYPE.FUND.getCode());
            merchantReportCertInfoList.add(merchantReportLegalDO);
        }
        if (merchantReportContactDO != null) {
            merchantReportContactDO.setType(MerchantEnum.CERT_INFO_TYPE.CONTACT.getCode());
            merchantReportContactDO.setRelationType(MerchantEnum.MERCHANT_COMMON_RELATION_TYPE.FUND.getCode());
            merchantReportCertInfoList.add(merchantReportContactDO);
        }
        if (CollectionUtils.isNotEmpty(merchantReportCertInfoList)) {
            merchantReportCertInfoList.stream().forEach(merchantReportBenefitDO -> {
                merchantReportBenefitDO.setRelationId(merchantReportInfoDO.getId());
                merchantReportBenefitDO.setRelationType(MerchantEnum.MERCHANT_COMMON_RELATION_TYPE.FUND.getCode());
                merchantReportBenefitDO.setSn(merchantReportInfoDO.getSn());
            });
        }
        if (merchantReportLicenseDO != null) {
            merchantLicenseMapper.insert(merchantReportLicenseDO);
        }
        merchantCardMapper.insert(merchantReportCardDO);
        if (CollectionUtils.isNotEmpty(merchantReportCertInfoList)) {
            merchantCertInfoMapper.insertBatch(merchantReportCertInfoList);
        }
        return merchantReportInfoDO.getId();
    }

    @Override
    public List<MerchantFundAccountBindDO> queryAccountBindList(String mchChannelCode) {
        LambdaQueryWrapperX<MerchantFundAccountBindDO> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.eqIfPresent(MerchantFundAccountBindDO::getMchChannelCode, mchChannelCode);
        queryWrapper.eqIfPresent(MerchantFundAccountBindDO::getSnVisible, 0);
        return merchantFundAccountBindMapper.selectList(queryWrapper);
    }

    @Override
    public List<MerchantFundAccountBindDO> queryAccountBindList(String mchChannelCode, CommonEnum.YES_NO_TYPE status, CommonEnum.YES_NO_TYPE fundProcessType) {
        LambdaQueryWrapperX<MerchantFundAccountBindDO> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.eqIfPresent(MerchantFundAccountBindDO::getMchChannelCode, mchChannelCode);
        queryWrapper.eqIfPresent(MerchantFundAccountBindDO::getStatus, status.getCode());
        queryWrapper.eqIfPresent(MerchantFundAccountBindDO::getFundProcessType, fundProcessType.getCode());
        return merchantFundAccountBindMapper.selectList(queryWrapper);
    }

    @Override
    public MerchantFundAccountDto queryAccountByMchOrderNo(String mchOrderNo) {
        MerchantFundAccountDO merchantFundAccountDO = merchantFundAccountMapper.selectOne(MerchantFundAccountDO::getMchOrderNo, mchOrderNo);
        if (merchantFundAccountDO == null) {
            return null;
        }
        MerchantFundAccountDto merchantFundAccountDto = new MerchantFundAccountDto();
        merchantFundAccountDto.setMerchantFundAccount(merchantFundAccountDO);
        merchantFundAccountDto.setMerchantFundCard(merchantCardMapper.selectOne(buildCardWrapper(merchantFundAccountDO.getId(), MerchantEnum.MERCHANT_COMMON_RELATION_TYPE.FUND)));
        return merchantFundAccountDto;
    }

    @Override
    public MerchantFundAccountDto queryAccountDetail(Long id) {
        MerchantFundAccountDO merchantFundAccountDO = merchantFundAccountMapper.selectById(id);
        if (merchantFundAccountDO == null) {
            return null;
        }
        MerchantFundAccountDto merchantFundAccountDto = new MerchantFundAccountDto();
        merchantFundAccountDto.setMerchantFundAccount(merchantFundAccountDO);
        merchantFundAccountDto.setMerchantFundCard(merchantCardMapper.selectOne(buildCardWrapper(merchantFundAccountDO.getId(), MerchantEnum.MERCHANT_COMMON_RELATION_TYPE.FUND)));
        merchantFundAccountDto
                .setMerchantFundLicense(merchantLicenseMapper.selectOne(buildLicenseWrapper(merchantFundAccountDO.getId(), MerchantEnum.MERCHANT_COMMON_RELATION_TYPE.FUND)));
        List<MerchantCertInfoDO> merchantAccessCertList = merchantCertInfoMapper.selectList(buildCertInfoWrapper(id, MerchantEnum.MERCHANT_COMMON_RELATION_TYPE.FUND));
        if (CollectionUtils.isEmpty(merchantAccessCertList)) {
            return merchantFundAccountDto;
        }
        Map<Integer, List<MerchantCertInfoDO>> merchantAccessCertMap = merchantAccessCertList.stream()
                .collect(Collectors.groupingBy(merchantAccessCertInfoDO -> merchantAccessCertInfoDO.getType()));
        List<MerchantCertInfoDO> legalList = merchantAccessCertMap.get(MerchantEnum.CERT_INFO_TYPE.LEGAL.getCode());
        List<MerchantCertInfoDO> contactList = merchantAccessCertMap.get(MerchantEnum.CERT_INFO_TYPE.CONTACT.getCode());
        if (CollectionUtils.isNotEmpty(legalList)) {
            merchantFundAccountDto.setMerchantFundLegal(legalList.get(0));
        }
        if (CollectionUtils.isNotEmpty(contactList)) {
            merchantFundAccountDto.setMerchantFundContact(contactList.get(0));
        }
        return merchantFundAccountDto;
    }

    @Override
    public MerchantFundAccountDO queryAccount(String mchChannelCode, String accountNo) {
        return merchantFundAccountMapper.selectOne(MerchantFundAccountDO::getMchChannelCode, mchChannelCode, MerchantFundAccountDO::getAccountNo, accountNo);
    }

    @Override
    public MerchantFundAccountBindDO queryAccountBind(String mchChannelCode, String accountNo) {
        return merchantFundAccountBindMapper.selectOne(MerchantFundAccountBindDO::getMchChannelCode, mchChannelCode, MerchantFundAccountBindDO::getAccountNo, accountNo);
    }

    @Override
    public void addAccountBind(MerchantFundAccountBindDO merchantFundAccountBindDO) {
        merchantFundAccountBindMapper.insert(merchantFundAccountBindDO);
    }

    @Override
    public void updateAccountBind(MerchantFundAccountBindDO merchantFundAccountBindDO) {
        merchantFundAccountBindMapper.updateById(merchantFundAccountBindDO);
    }

    @Override
    public void updateAccountStatus(Long id, CommonEnum.YES_NO_TYPE yesNoType) {
        MerchantFundAccountBindDO merchantFundAccountBindDO = new MerchantFundAccountBindDO();
        merchantFundAccountBindDO.setId(id);
        merchantFundAccountBindDO.setStatus(yesNoType.getCode());
        merchantFundAccountBindMapper.updateById(merchantFundAccountBindDO);
    }

    @Override
    public void updateAccount(MerchantFundAccountDO updateFundAccountDO) {
        merchantFundAccountMapper.updateById(updateFundAccountDO);
    }

    @Override
    public void updateFundCard(MerchantFundAccountDto merchantFundAccountDto) {
        MerchantFundAccountDO merchantReportInfoDO = merchantFundAccountDto.getMerchantFundAccount();
        MerchantCardDO merchantReportCardDO = merchantFundAccountDto.getMerchantFundCard();
        if (merchantReportCardDO != null) {
            merchantReportCardDO.setRelationId(merchantReportInfoDO.getId());
            merchantReportCardDO.setRelationType(MerchantEnum.MERCHANT_COMMON_RELATION_TYPE.FUND.getCode());
            merchantReportCardDO.setSn(merchantReportInfoDO.getSn());
        }

        merchantCardMapper.delete(buildCardWrapper(merchantReportInfoDO.getId(), MerchantEnum.MERCHANT_COMMON_RELATION_TYPE.FUND));
        merchantCardMapper.insert(merchantReportCardDO);
    }

    @Override
    public PageResult<MerchantFundPageDto> queryPage(FundAccountQueryDto fundAccountQueryDto) {
        if (!StringUtils.hasText(fundAccountQueryDto.getSortingFields())) {
            fundAccountQueryDto.setSortingFields("a.id");
        }
        IPage<MerchantFundPageDto> mpPage = MyBatisUtils.buildPage(fundAccountQueryDto);
        QueryWrapper<MerchantFundPageDto> queryWrapper = buildInfoWrapper(fundAccountQueryDto);
        // queryWrapper.orderByDesc("a.id");
        merchantFundAccountMapper.selectAccountPage(mpPage, queryWrapper);
        return new PageResult(mpPage.getRecords(), mpPage.getTotal(), mpPage.getCurrent(), mpPage.getSize(), mpPage.getPages());
    }
    @Override
    public List<MerchantFundPageDto> queryList(FundAccountQueryDto fundAccountQueryDto) {
        if (!StringUtils.hasText(fundAccountQueryDto.getSortingFields())) {
            fundAccountQueryDto.setSortingFields("a.id");
        }
        QueryWrapper<MerchantFundPageDto> queryWrapper = buildInfoWrapper(fundAccountQueryDto);
        // queryWrapper.orderByDesc("a.id");
        return merchantFundAccountMapper.selectAccountList(queryWrapper);
    }

    @Override
    public void delAccountBind(Long id) {
        merchantFundAccountBindMapper.deleteById(id);
    }

    @Override
    public void delAccount(Long id) {
        merchantFundAccountMapper.deleteById(id);
    }


    /**
     * 查询条件封装
     *
     * @param relationId
     * @param relationType
     * @return
     */
    LambdaQueryWrapper<MerchantCertInfoDO> buildCertInfoWrapper(Long relationId, MerchantEnum.MERCHANT_COMMON_RELATION_TYPE relationType) {
        LambdaQueryWrapperX<MerchantCertInfoDO> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.eqIfPresent(MerchantCertInfoDO::getRelationId, relationId);
        queryWrapper.eqIfPresent(MerchantCertInfoDO::getRelationType, relationType.getCode());
        return queryWrapper;
    }

    /**
     * 查询条件封装
     *
     * @param relationId
     * @param relationType
     * @return
     */
    LambdaQueryWrapper<MerchantLicenseDO> buildLicenseWrapper(Long relationId, MerchantEnum.MERCHANT_COMMON_RELATION_TYPE relationType) {
        LambdaQueryWrapperX<MerchantLicenseDO> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.eqIfPresent(MerchantLicenseDO::getRelationId, relationId);
        queryWrapper.eqIfPresent(MerchantLicenseDO::getRelationType, relationType.getCode());
        return queryWrapper;
    }

    /**
     * 查询条件封装
     *
     * @param relationId
     * @param relationType
     * @return
     */
    LambdaQueryWrapper<MerchantCardDO> buildCardWrapper(Long relationId, MerchantEnum.MERCHANT_COMMON_RELATION_TYPE relationType) {
        LambdaQueryWrapperX<MerchantCardDO> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.eqIfPresent(MerchantCardDO::getRelationId, relationId);
        queryWrapper.eqIfPresent(MerchantCardDO::getRelationType, relationType.getCode());
        return queryWrapper;
    }
    private QueryWrapper<MerchantFundPageDto> buildInfoWrapper(FundAccountQueryDto fundAccountQueryDto) {
        filterSn(fundAccountQueryDto);
        QueryWrapperX<MerchantFundPageDto> queryWrapper = new QueryWrapperX<>();
        queryWrapper.eq("a.delete_flag", CommonEnum.YES_NO_TYPE.NO.getCode());
        queryWrapper.eqIfPresent("a.sn", fundAccountQueryDto.getSn());
        queryWrapper.inIfPresent("a.sn", fundAccountQueryDto.getSnList());
        queryWrapper.likeIfPresent("a.account_no", fundAccountQueryDto.getAccountNo());
        queryWrapper.eqIfPresent("a.status", fundAccountQueryDto.getStatus());
        queryWrapper.likeIfPresent("a.name", fundAccountQueryDto.getName());
        queryWrapper.likeIfPresent("a.request_id", fundAccountQueryDto.getRequestId());
        queryWrapper.geIfPresent("a.create_time", fundAccountQueryDto.getStartQueryTime());
        queryWrapper.leIfPresent("a.create_time", fundAccountQueryDto.getEndQueryTime());
        queryWrapper.eqIfPresent("a.mch_channel_code", fundAccountQueryDto.getMchChannelCode());
        queryWrapper.eqIfPresent("a.fund_process_type", fundAccountQueryDto.getFundProcessType());
        queryWrapper.likeIfPresent("b.phone", fundAccountQueryDto.getContactPhone());
        queryWrapper.likeIfPresent("b.name", fundAccountQueryDto.getContactName());
        queryWrapper.likeIfPresent("b.other_value", fundAccountQueryDto.getContactEmail());
        queryWrapper.likeIfPresent("c.provider_code", fundAccountQueryDto.getProviderCode());
        queryWrapper.eqIfPresent("c.channel_code", fundAccountQueryDto.getChannelCode());
        queryWrapper.likeIfPresent("d.super_agent", fundAccountQueryDto.getSuperAgent());
        return queryWrapper;
    }
}
